/*
 * Copyright (c) 2010-2011, Petr Panteleyev <petr@panteleyev.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.blogclient.photo;

import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JScrollPane;
import javax.swing.JTable;

import org.panteleyev.blogclient.Icon;
import org.panteleyev.swing.BaseTable;
import org.panteleyev.swing.TableUtil;

import com.google.common.collect.ImmutableList;
import javax.swing.JMenu;
import org.panteleyev.swing.BaseFrame;
import org.panteleyev.swing.BasePanel;
import org.panteleyev.swing.MenuProvider;

public abstract class ThumbnailPanel<F extends BaseFrame,P> extends BasePanel<F> implements MenuProvider {
    protected static final String PHOTO_MENU_NAME = L10N.PHOTO_MENU_NAME.s();

    private ArrayList<P>                    pictures = new ArrayList<>();
    private final ArrayList<ImageIcon>      thumbnails = new ArrayList<>();
    private ThumbnailTableModel             tableModel = new ThumbnailTableModel(thumbnails);
    private JTable                          table = new BaseTable(tableModel);
    private JScrollPane                     scroller = new JScrollPane(table);
    private ReentrantLock                   thumbnailsLock = new ReentrantLock();
    private JMenu                           menu;

    private final Runnable updateWindowEDT = new Runnable() {
        @Override
        public void run() {
            try {
                getThumbnailsLock().lock();
                if (!getTableModel().calculateTableLayout(getScroller().getSize().width, getCellWidth())) {
                    getTableModel().fireTableDataChanged();
                }
                TableUtil.adjustTableColumnSizes(getTable());
                TableUtil.adjustTableRowSizes(getTable());
            } finally {
                getThumbnailsLock().unlock();
            }
        }
    };

    protected class PicturePropertiesAction extends AbstractAction {
        public PicturePropertiesAction() {
            super(L10N.PROPERTIES_ACTION.s(), Icon.EMPTY.i());
            putValue(Action.SHORT_DESCRIPTION, L10N.PROPERTIES_ACTION.s());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            P picture = getSelectedPicture();
            if (picture != null) {
                onPictureProperties(picture);
            }
        }
    }

    protected class PictureOpenWebAction extends AbstractAction {
        public PictureOpenWebAction() {
            super(L10N.PHOTO_PAGE_ACTION.s(), Icon.EARTH.i());
            putValue(Action.SHORT_DESCRIPTION, L10N.PHOTO_PAGE_ACTION.s());
            putValue(Action.LARGE_ICON_KEY, Icon.EARTH.I());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            P picture = getSelectedPicture();
            if (picture != null) {
                pictureDoubleClicked(picture);
            }
        }
    }

    protected class PictureUploadAction extends AbstractAction {
        public PictureUploadAction() {
            super(L10N.UPLOAD_ACTION.s(), Icon.UPLOAD.i());
            putValue(Action.SHORT_DESCRIPTION, L10N.UPLOAD_ACTION.s());
            putValue(Action.LARGE_ICON_KEY, Icon.UPLOAD.I());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            onUpload();
        }
    }

    protected class PublichPucturesAction extends AbstractAction {
        public PublichPucturesAction() {
            super(L10N.PUBLISH_ACTION.s(), Icon.EMPTY.i());
            putValue(Action.SHORT_DESCRIPTION, L10N.PUBLISH_ACTION.s());
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            ImmutableList<P> selection = getSelectedPictures();
            if (selection.size() != 0) {
                onPublishPictures(selection);
            }
        }
    }

    public ThumbnailPanel(F frame) {
        super(frame);
        table.setTableHeader(null);
///        getTable().setColumnSelectionAllowed(true);
        table.setCellSelectionEnabled(true);
        table.setDefaultRenderer(ImageIcon.class, new ThumbnailRenderer());
        table.setShowGrid(false);

        table.addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                if (evt.getClickCount() == 2) {
                    P picture = getSelectedPicture();
                    if (picture != null) {
                        pictureDoubleClicked(picture);
                    }
                }
            }
        });

        scroller.addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent evt) {
                if (tableModel.calculateTableLayout(scroller.getSize().width, getCellWidth())) {
                    TableUtil.adjustTableColumnSizes(table);
                    TableUtil.adjustTableRowSizes(table);
                }
            }
        });
    }

    public ReentrantLock getThumbnailsLock() {
        return thumbnailsLock;
    }

    public Runnable getUpdateWindowEDT() {
        return updateWindowEDT;
    }

    public JScrollPane getScroller() {
        return scroller;
    }

    public JTable getTable() {
        return table;
    }

    public ThumbnailTableModel getTableModel() {
        return tableModel;
    }

    public ArrayList<ImageIcon> getThumbnails() {
        return thumbnails;
    }

    public ArrayList<P> getPictures() {
        return pictures;
    }

    public void setPictures(ArrayList<P> pictures) {
        this.pictures = pictures;
    }

    protected P getSelectedPicture() {
        int row = table.getSelectedRow();
        int col = table.getSelectedColumn();

        if ((row != -1) && (col != -1)) {
            int index = row * tableModel.getColumnCount() + col;
            try {
                return pictures.get(index);
            } catch (IndexOutOfBoundsException e) {
                return null;
            }
        } else {
            return null;
        }
    }

    protected ImmutableList<P> getSelectedPictures() {
        ArrayList<P> selection = new ArrayList<>(pictures.size());
        for (int row = 0; row < getTableModel().getRowCount(); row++) {
            for (int col = 0; col < getTableModel().getColumnCount(); col++) {
                if (getTable().isCellSelected(row, col)) {
                    int index = row * getTableModel().getColumnCount() + col;
                    if (index < pictures.size()) {
                        selection.add(pictures.get(index));
                    }
                }
            }
        }

        return ImmutableList.copyOf(selection);
    }

    @Override
    public JMenu getMenu() {
        return (menu == null) ? menu = createMenu() : menu;
    }

    abstract protected int getCellWidth();
    abstract protected void pictureDoubleClicked(P picture);
    abstract protected void onPictureProperties(P picture);
    abstract protected void onPublishPictures(ImmutableList<P> pictures);

    protected void onUpload() {
    }
}
